package info.hexin.aop3.test1;

import info.hexin.aop3.AopInjectClass;
import info.hexin.aop3.AopInjectClass1;
import info.hexin.aop3.AsmClassLoader;
import info.hexin.aop3.ClassAdapter;
import info.hexin.aop3.Foo;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

public class ClassWriterAopExample1 implements Opcodes {

    public static void main(String[] args) throws Exception {

        System.out.println(Type.getDescriptor(AopInjectClass1.class));

        AsmClassLoader asmClassLoader = new AsmClassLoader();
        Thread.currentThread().setContextClassLoader(asmClassLoader);
        Class.forName(AopInjectClass.class.getName());

        ClassReader cr = new ClassReader(Foo.class.getName());
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cr.accept(new ClassAdapter(Opcodes.ASM4, cw), 0);

        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "execute", "()V", null, null);
        // 开始增加代码
        mv.visitCode();

        mv.visitMethodInsn(INVOKESTATIC, "info/hexin/aop3/AopInjectClass", "test1", "()V");

        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(0, 0); // 这个地方，最大的操作数栈和最大的本地变量的空间，是自动计算的，是因为构造ClassWriter的时候使用了ClassWriter.COMPUTE_MAXS
        mv.visitEnd();

        Thread.currentThread().setContextClassLoader(asmClassLoader);
        Class<?> c = asmClassLoader.defineClassFromClassFile("info.hexin.aop3.Foo$1", cw.toByteArray());
        invoke(c);

    }

    private static void invoke(Class<?> c) throws InstantiationException, IllegalAccessException,
            NoSuchMethodException, InvocationTargetException {
        Object instances = c.newInstance();
        Method m = c.getMethod("execute", null);
        m.invoke(instances, null);
    }

    private static void printmethod(Class<?> c) {
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}
